import { readFile } from "fs/promises";
import { createHash } from "crypto";
import path from "path";
import { ICodeParser, CodeBlock } from "../interfaces/index.js";
import { SUPPORTED_EXTENSIONS } from "../constants/index.js";
import { envConfig } from "../config/env-config.js";

/**
 * A simple parser that implements a sliding window strategy for all file types.
 */
export class SimpleCodeParser implements ICodeParser {
  
  async parseFile(
    filePath: string,
    options?: {
      content?: string;
      fileHash?: string;
    },
  ): Promise<CodeBlock[]> {
    const ext = path.extname(filePath).toLowerCase();
    if (!this.isSupportedLanguage(ext)) {
      return [];
    }

    let content: string;
    let fileHash: string;

    if (options?.content) {
      content = options.content;
      fileHash = options.fileHash || this.createFileHash(content);
    } else {
      try {
        content = await readFile(filePath, "utf8");
        fileHash = this.createFileHash(content);
      } catch (error) {
        console.error(`Error reading file ${filePath}:`, error);
        return [];
      }
    }

    return this.slidingWindowParse(filePath, content, fileHash);
  }

  private isSupportedLanguage(extension: string): boolean {
    return SUPPORTED_EXTENSIONS.includes(extension);
  }

  private createFileHash(content: string): string {
    return createHash("sha256").update(content).digest("hex");
  }

  /**
   * Implements a sliding window chunking strategy.
   */
  private slidingWindowParse(filePath: string, content: string, fileHash: string): CodeBlock[] {
    const { CHUNK_SIZE, CHUNK_OVERLAP } = envConfig;
    const blocks: CodeBlock[] = [];
    const lines = content.split('\n');
    const seenHashes = new Set<string>();

    let text = content;
    let start = 0;
    let lineCounter = 1;
    let startLine = 1;

    while (start < text.length) {
      const end = Math.min(start + CHUNK_SIZE, text.length);
      const chunkContent = text.substring(start, end);
      
      // Find the end line number for the chunk
      const chunkLines = chunkContent.split('\n').length - 1;
      const endLine = startLine + chunkLines;

      const block = this.createBlock(
        filePath,
        chunkContent,
        startLine,
        endLine,
        fileHash,
        seenHashes
      );

      if (block) {
        blocks.push(block);
      }

      // Move the window
      start += CHUNK_SIZE - CHUNK_OVERLAP;
      
      // Update the start line number for the next chunk
      const overlapContent = text.substring(start, Math.min(start + CHUNK_OVERLAP, text.length));
      const linesInStep = text.substring(0, start).split('\n').length;
      startLine = linesInStep;
    }

    return blocks;
  }

  private createBlock(
    filePath: string,
    content: string,
    startLine: number,
    endLine: number,
    fileHash: string,
    seenHashes: Set<string>
  ): CodeBlock | null {
    const trimmedContent = content.trim();
    if (trimmedContent.length === 0) {
      return null;
    }

    const segmentHash = createHash("sha256")
      .update(`${filePath}-${startLine}-${endLine}-${trimmedContent}`)
      .digest("hex");

    if (seenHashes.has(segmentHash)) {
      return null;
    }
    seenHashes.add(segmentHash);

    return {
      file_path: filePath,
      identifier: null,
      type: 'chunk',
      start_line: startLine,
      end_line: endLine,
      content: trimmedContent,
      segmentHash,
      fileHash,
    };
  }
}

export const simpleCodeParser = new SimpleCodeParser();
